package com.zhx.common.websocket.handle;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.zhx.common.websocket.domain.enums.WSReqTypeEnum;
import com.zhx.common.websocket.domain.vo.req.WSBaseReq;
import com.zhx.common.websocket.service.WebSocketService;
import com.zhx.common.websocket.util.NettyUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;


/**
 * @ChannelHandler.Sharable 用于指示一个ChannelHandler是可以共享的。
 * 这意味着同一个ChannelHandler实例可以在多个Channel上使用，而不需要为每个Channel创建一个新的实例。
 */
@ChannelHandler.Sharable
@Slf4j
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private WebSocketService webSocketService;

    // 连接刚建立时会触发此方法，刚进入网页的时候就会连接wb，这时候就已经可以接受新消息推送啦。
    // 不过目前这个连接是一个未登录的用户。需要进行登录认证。
    // 将连接放入一个map中管理，目前该连接是未登录态。
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("连接建立");
        webSocketService = SpringUtil.getBean(WebSocketService.class);
        webSocketService.connect(ctx.channel());
    }

    //客户端断开连接会触发
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        userOffline(ctx.channel());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            System.out.println("握手完成");
            String token = NettyUtil.getAttr(ctx.channel(), NettyUtil.TOKEN);
            //token为空说明是还没有登录，这里token不为空才需要进行登录认证
            if(StrUtil.isNotBlank(token)){
                webSocketService.authorize(ctx.channel(), token);
            }

        } else if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                System.out.println("读空闲事件");
                userOffline(ctx.channel());
            }
        }
        //重写握手逻辑后的握手事件
//        else if(evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE){
//            System.out.println("握手请求");
//            Attribute<Object> token1 = ctx.channel().attr(AttributeKey.valueOf("token"));
//            webSocketService.authorize(ctx.channel(),token1.get().toString());
//        }
    }

    private void userOffline(Channel channel) {
        this.webSocketService.remove(channel);
        channel.close();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        String text = msg.text();
        WSBaseReq wsBaseReq = JSONUtil.toBean(text, WSBaseReq.class);

        switch (WSReqTypeEnum.of(wsBaseReq.getType())) {
            //前端点击登录，会发出一个请求登录二维码的websocket信息。
            case LOGIN:
                System.out.println("请求二维码...");
                webSocketService.handleLoginReq(ctx.channel());
                break;
            case AUTHORIZE:
                System.out.println("登陆认证 type=3");
                webSocketService.authorize(ctx.channel(),wsBaseReq.getData());
                break;
            case HEARTBEAT:
                System.out.println("心跳包");
                break;
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("exceptionCaught",cause);
        super.exceptionCaught(ctx, cause);
    }
}
